package com.ryan.demo.xstream.mas.parser.converter;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.util.ReflectionUtils;

import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
import com.thoughtworks.xstream.mapper.Mapper;

/**
 * @Project mas
 * @Description 自定义XStream转换器
 * @Company 99bill
 * @Create 2012-2-16
 * @author qingyou.lin
 */
public class ReflectionExtConverter extends ReflectionConverter {
	
	/**
	 * logger
	 */
	protected static final Logger logger = Logger.getLogger(ReflectionExtConverter.class);
	
	
	private final Map<Class<?>, WeakReference<List<Method>>> loaderCache = new HashMap<Class<?>, WeakReference<List<Method>>>();

	public ReflectionExtConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
		super(mapper, reflectionProvider);
		logger.debug("creating new ReflectExtConverter...");
	}

	@SuppressWarnings("rawtypes")
	@Override
	protected Object unmarshallField(UnmarshallingContext context, Object result, Class type, Field field) {

		Object obj = super.unmarshallField(context, result, type, field);
		try {
			Method method = getFromLocalCache(result);
			if (method != null) {
				method.invoke(result, new Object[] { field.getName(), obj });
			}
		} catch (Exception e) {
			logger.error("XStream self-defined Converter unmarshalling error...", e);
		}
		return obj;
	}

	private Method getFromLocalCache(Object result) {
		Class<?> clazz = result.getClass();
		WeakReference<List<Method>> ref = loaderCache.get(clazz);
		if (ref != null) {
			List<Method> list = ref.get();
			if (list != null) {
				return list.get(0);
			}
		}
		Method method = ReflectionUtils.findMethod(clazz, "addPropInfo", new Class[] { String.class, Object.class });
		List<Method> list = new ArrayList<Method>(1);
		list.add(method);
		loaderCache.put(clazz, new WeakReference<List<Method>>(list));
		return method;
	}

}
